package nnet2.net;

import java.util.Random;

public class Layer implements ILayer {

	private boolean bias = true;
	private float[][] changes;
	private float[] errors;
	private float[] values;
	private float[][] weights;

	public Layer(int len, int prevLen, float min, float max) {
		len = len + 1;
		this.errors = new float[len];
		this.values = new float[len];
		this.changes = new float[len][prevLen];
		this.weights = new float[len][prevLen];
		this.initWeights(min, max);
	}

	public Layer(int len, int prevLen, float min, float max, boolean bs) {
		if (bs)
			len = len + 1;
		bias = bs;
		this.errors = new float[len];
		this.values = new float[len];
		this.changes = new float[len][prevLen];
		this.weights = new float[len][prevLen];
		this.initWeights(min, max);
	}

	@Override
	public void calculate(float[] prev) {
		float sum = 0f;
		for (int i = 0; i < values.length; i++) {
			sum = 0f;
			for (int j = 0; j < prev.length; j++) {
				sum += this.weights[i][j] * prev[j];
			}
			this.values[i] = f(sum);
		}
	}

	private float f(float x) {
		return 1 / (1 + (float) Math.exp(-x));
	}

	private float df(float x) {
		return (1 - f(x)) * f(x);
	}

	@Override
	public boolean getBias() {
		return bias;
	}

	@Override
	public float[][] getChanges() {
		return changes;
	}

	@Override
	public float[] getErrors() {
		return errors;
	}

	@Override
	public float[] getValues() {
		return values;
	}

	@Override
	public float[][] getWeights() {
		return weights;
	}

	@Override
	public void setChanges(float[][] ch) {
		if (ch.length == changes.length && ch[0].length == changes[0].length)
			changes = ch;
		else
			throw new SizeMismatchException(changes, ch);

	}

	@Override
	public void setErrors(float[] err) {
		if (err.length == errors.length)
			errors = err;
		else
			throw new SizeMismatchException(errors.length, err.length);

	}

	@Override
	public void setWeights(float[][] wg) {
		if (wg.length == weights.length && wg[0].length == weights[0].length)
			weights = wg;
		else
			throw new SizeMismatchException(weights, wg);

	}

	private void initWeights(float min, float max) {
		Random r = new Random();
		float diff = max - min;
		for (int i = 0; i < weights.length; i++) {
			for (int j = 0; j < weights[0].length; j++) {
				weights[i][j] = (r.nextFloat() * diff) + min;
			}
		}
	}

	@Override
	public int getSize() {
		return this.values.length;
	}

}
